package com.example.blog.config;

import com.example.blog.model.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
//统一返回类型
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        //设置这个，拦截器启动
        return true;
    }
//    这段代码是一个beforeBodyWrite方法，看起来像是Spring框架中的ResponseBodyAdvice接口的一个实现，用于在HTTP响应体写入之前对响应体进行处理。
//    在这个方法中，对响应体body进行了检查和处理：
//    如果body是Result类型的实例，则直接返回body，不做任何修改。
//    如果body是String类型的实例，则使用objectMapper将其转换为JSON格式的字符串，并将这个字符串包装在Result.success中返回。
//    如果body既不是Result类型也不是String类型，则将其包装在Result.success中返回。
//
//    如果你去掉对String类型的判断，那么所有非Result类型的响应体都会被包装在Result.success中返回。这包括那些已经是JSON格式字符串的响应体，或者是其他类型的响应体。
//
//    对于已经是JSON格式字符串的响应体，这可能会导致双重序列化的问题。因为Result.success(body)会将body（此时是一个JSON格式的字符串）再次序列化成一个JSON对象，导致返回的响应体是嵌套的JSON字符串。这通常不是你想要的结果，因为它会使前端解析响应体变得复杂，并且可能引发错误。
//
//    对于其他类型的响应体，虽然它们会被正确地包装在Result.success中返回，但你可能失去了对原始响应体类型的控制。这意味着，即使你的原始响应体是一个复杂的对象或集合，它也会被序列化为一个JSON字符串，并被包装在Result对象中。这可能不是你想要的行为，特别是当你需要保持原始响应体的类型或结构时。
//
//    因此，保留对String类型的判断是很重要的，它可以确保已经是JSON格式字符串的响应体不会被错误地再次序列化。
    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
     //这个地方发生的情况是会报一个嵌套的Result
        if(body instanceof Result){
         return body;
     }
        ////    如果body是String类型的实例，则使用objectMapper将其转换为JSON格式的字符串，并将这个字符串包装在Result.success中返回。
        //会有内部一个方法String和Result类型不匹配而去报错
        //它转化成JSON类型，就可以走这一条路
     if(body instanceof String){
         ObjectMapper objectMapper=new ObjectMapper();
         return objectMapper.writeValueAsString(Result.success(body));
     }
        return Result.success(body);
    }
}
